﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;

namespace LINQToolKit
{
    public static class ArgumentExt
    {
        public static Uri Encode(this Uri source)
        {
            var sbUrl = new StringBuilder();
            sbUrl.Append(source.Scheme + "://" + source.Host);
            // encode absolute path
            var paths = source.AbsolutePath.Trim('/').Split('/');
            foreach (var p in paths)
            {
                sbUrl.Append("/" + HttpUtility.UrlEncode(p));
            }

            var queryString = source.Query.Trim('?', '&');

            if (!string.IsNullOrEmpty(queryString))
            {
                var queries = queryString.Split('&');
                sbUrl.Append("?");

                foreach (var q in queries)
                {
                    var segs = q.Split('=');

                    if (segs.Length > 1)
                    {
                        sbUrl.AppendFormat("{0}={1}&", segs[0], HttpUtility.UrlEncode(segs[1]));
                    }
                    else
                    {
                        sbUrl.Append(HttpUtility.UrlEncode(q) + "&");
                    }
                }
            }

            return new Uri(sbUrl.ToString());
        }

        //public static bool IsEvaluatableFrom(this Type source, Type toCheck)
        //{
        //    if (source.IsGenericType && toCheck.IsGenericType)
        //    {
        //        source = source.GetGenericTypeDefinition();

        //        if (source.IsInterface)
        //        {
        //            var query =
        //                from f in toCheck.GetInterfaces()
        //                where f.IsGenericType &&
        //                    f.GetGenericTypeDefinition() == source
        //                select f;

        //            return query.Count() > 0;
        //        }
        //        else
        //        {
        //            while (toCheck != null && toCheck.GetType() != typeof(object))
        //            {
        //                toCheck = toCheck.GetGenericTypeDefinition();

        //                if (toCheck == source)
        //                {
        //                    return true;
        //                }

        //                toCheck = toCheck.BaseType;
        //            }

        //            return false;
        //        }
        //    }
        //    else if (!(source.IsGenericType || toCheck.IsGenericType))
        //    {
        //        return source.IsAssignableFrom(toCheck);
        //    }

        //    return false;
        //}

        public static void AssertType(this object source, string argName, Type type)
        {
            ArgumentExt.AssertType(source, argName, type, string.Empty);
        }

        public static void AssertType(this object source, string argName, Type type, string message)
        {
            ArgumentExt.AssertNull(type, "type");
            ArgumentExt.AssertNull(source, argName, message);

            if (!type.IsAssignableFrom(source.GetType()))
            {
                throw new ArgumentException(message, argName);
            }
        }

        public static void AssertNull(this object source, string argName)
        {
            ArgumentExt.AssertNull(source, argName, string.Empty);
        }

        public static void AssertNull(this object source, string argName, string message)
        {
            if (source == null)
            {
                throw new ArgumentNullException(argName, message);
            }
        }

        public static void AssertNull(this string source, string argName)
        {
            ArgumentExt.AssertNull(source, argName, string.Empty);
        }

        public static void AssertNull(this string source, string argName, string message)
        {
            if (string.IsNullOrEmpty(source))
            {
                throw new ArgumentNullException(argName, message);
            }
        }
    }
}
